package com.learning.dubbo.registry.custom.registry;

import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.URLBuilder;
import org.apache.dubbo.common.URLStrParser;
import org.apache.dubbo.common.utils.CollectionUtils;
import org.apache.dubbo.common.utils.UrlUtils;
import org.apache.dubbo.registry.NotifyListener;
import org.apache.dubbo.registry.support.FailbackRegistry;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static org.apache.dubbo.common.constants.CommonConstants.ANY_VALUE;
import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PATH_SEPARATOR;
import static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_SEPARATOR_ENCODED;
import static org.apache.dubbo.common.constants.RegistryConstants.CATEGORY_KEY;
import static org.apache.dubbo.common.constants.RegistryConstants.CONFIGURATORS_CATEGORY;
import static org.apache.dubbo.common.constants.RegistryConstants.CONSUMERS_CATEGORY;
import static org.apache.dubbo.common.constants.RegistryConstants.DEFAULT_CATEGORY;
import static org.apache.dubbo.common.constants.RegistryConstants.EMPTY_PROTOCOL;
import static org.apache.dubbo.common.constants.RegistryConstants.PROVIDERS_CATEGORY;
import static org.apache.dubbo.common.constants.RegistryConstants.ROUTERS_CATEGORY;

/**
 * ClassName: EsbpCustomRegistry
 * Description: Esbp 注册中心扩展
 * Date: 2020/8/27 9:46 【需求编号】
 *
 * @author Sam Sho
 * @version V1.0.0
 */
@Slf4j
public class EsbpCustomRegistry extends FailbackRegistry {

    private final String root;
    private final static String DEFAULT_ROOT = "dubbo";

    private static HashMap<String, String> registry = Maps.newHashMap();

    public EsbpCustomRegistry(URL url) {
        super(url);
        log.info("~~~~~url: {} ~~~~~", url);

        String organization = url.getParameter("organization");
        String owner = url.getParameter("owner");
        String version = url.getParameter("version");

        String username = url.getUsername();
        String password = url.getPassword();

        // 启动 agent
        String serviceInterface = url.getServiceInterface();

        String group = url.getParameter(GROUP_KEY, DEFAULT_ROOT);
        if (!group.startsWith(PATH_SEPARATOR)) {
            group = PATH_SEPARATOR + group;
        }
        this.root = group;
    }

    @Override
    public void doRegister(URL url) {
        // providers:  dubbo://2.0.1.46:20880/com.learning.dubbo.registry.custom.api.GreetingsService?anyhost=true&application=dubbo-registry-custom-provider&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=com.learning.dubbo.registry.custom.api.GreetingsService&methods=sayHi&pid=3968&release=2.7.7&side=provider&timestamp=1598600841897

        // consumer:   consumer://2.0.1.46/com.learning.dubbo.registry.custom.api.GreetingsService?application=dubbo-registry-custom-consumer&category=consumers&check=false&dubbo=2.0.2&init=false&interface=com.learning.dubbo.registry.custom.api.GreetingsService&methods=sayHi&pid=9896&release=2.7.7&side=consumer&sticky=false&timestamp=1598601299308~~~~~~

        String category = url.getParameter(CATEGORY_KEY, DEFAULT_CATEGORY);
        if (DEFAULT_CATEGORY.equals(category)) {
            log.info("~~~~ 注册服务开始 {}~~~~~~", url);

            String categoryPath = toCategoryPath(url);
            String serviceAddress = URL.encode(url.toFullString());
            registry.put(categoryPath, serviceAddress);


            /*String serviceInterface = url.getServiceInterface();
            String ip = url.getIp();
            String host = url.getHost();
            int port = url.getPort();
            String username = url.getUsername();
            String password = url.getPassword();
            String serviceKey = url.getServiceKey();
            String address = url.getAddress();
            String authority = url.getAuthority();
            String backupAddress = url.getBackupAddress();
            Map<String, String> parameters = url.getParameters();
            String application = url.getParameter("application");*/

            log.info("~~~~ 服务 {} 注册成功~~~~~~", categoryPath);
        }
    }

    @Override
    public void doUnregister(URL url) {
        log.info("~~~~ 订阅服务 {}~~~~~~", url);

    }

    @Override
    public void doSubscribe(URL url, NotifyListener listener) {
        log.info("~~~~ 订阅服务开始 {}~~~~~~", url);
        List<URL> urls = new ArrayList<>();

        for (String path : toCategoriesPath(url)) {
            String serviceAddress = registry.get(path);
            if (!Strings.isNullOrEmpty(serviceAddress)) {
                urls.addAll(toUrlsWithEmpty(url, path, Lists.newArrayList(serviceAddress)));
            }
        }
        EsbpCustomRegistry.this.notify(url, listener, urls);
    }

    @Override
    public void doUnsubscribe(URL url, NotifyListener listener) {
        log.info("~~~~ doUnsubscribe {}~~~~~~", url);
    }

    @Override
    public boolean isAvailable() {
        return true;
    }

    private String[] toCategoriesPath(URL url) {
        String[] categories;
        if (ANY_VALUE.equals(url.getParameter(CATEGORY_KEY))) {
            categories = new String[]{PROVIDERS_CATEGORY, CONSUMERS_CATEGORY, ROUTERS_CATEGORY, CONFIGURATORS_CATEGORY};
        } else {
            categories = url.getParameter(CATEGORY_KEY, new String[]{DEFAULT_CATEGORY});
        }
        String[] paths = new String[categories.length];
        for (int i = 0; i < categories.length; i++) {
            paths[i] = toServicePath(url) + PATH_SEPARATOR + categories[i];
        }
        return paths;
    }

    private List<URL> toUrlsWithEmpty(URL consumer, String path, List<String> providers) {
        List<URL> urls = toUrlsWithoutEmpty(consumer, providers);
        if (urls == null || urls.isEmpty()) {
            int i = path.lastIndexOf(PATH_SEPARATOR);
            String category = i < 0 ? path : path.substring(i + 1);
            URL empty = URLBuilder.from(consumer)
                    .setProtocol(EMPTY_PROTOCOL)
                    .addParameter(CATEGORY_KEY, category)
                    .build();
            urls.add(empty);
        }
        return urls;
    }

    private List<URL> toUrlsWithoutEmpty(URL consumer, List<String> providers) {
        List<URL> urls = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(providers)) {
            for (String provider : providers) {
                if (provider.contains(PROTOCOL_SEPARATOR_ENCODED)) {
                    URL url = URLStrParser.parseEncodedStr(provider);
                    if (UrlUtils.isMatch(consumer, url)) {
                        urls.add(url);
                    }
                }
            }
        }
        return urls;
    }

    private String toServicePath(URL url) {
        return root + PATH_SEPARATOR + url.getServiceInterface();
    }

    private String toCategoryPath(URL url) {
        return toServicePath(url) + PATH_SEPARATOR + url.getParameter(CATEGORY_KEY, DEFAULT_CATEGORY);
    }

    private String toUrlPath(URL url) {
        return toCategoryPath(url) + PATH_SEPARATOR + URL.encode(url.toFullString());
    }


}
